﻿using System.Reflection;
using Castle.MicroKernel.Registration;
using Castle.MicroKernel;
using System.Xml;
using Castle.Core.Configuration;
using Castle.Core.Configuration.Xml;
using System;
using Inovout.Model;
using System.IO;
using NHibernate.Tool.hbm2ddl;

namespace Inovout.Repository
{
    public class RepositoryInstaller : ComponentInstaller
    {

        protected override void Register()
        {
            XmlDocument xmlDocument = new XmlDocument();
            xmlDocument.Load("Configs\\DataSource.config");
            IConfiguration dataSourceConfiguration = XmlConfigurationDeserializer.GetDeserializedNode(xmlDocument.DocumentElement);

            IConfiguration nhFacilityConfiguration = new MutableConfiguration("facility");
            nhFacilityConfiguration.Attributes["type"] = typeof(NHibernateExtensionFacility).AssemblyQualifiedName;
            nhFacilityConfiguration.Attributes["id"] = "nhibernatefacility";
            nhFacilityConfiguration.Attributes["configurationBuilder"] = typeof(DatabaseConfigurationBuilder).AssemblyQualifiedName;
            nhFacilityConfiguration.Children.AddRange(dataSourceConfiguration.Children["databases"].Children);

            Container.Kernel.ConfigurationStore.AddFacilityConfiguration(typeof(NHibernateExtensionFacility).FullName, nhFacilityConfiguration);
            Container.AddFacility(typeof(NHibernateExtensionFacility).FullName, new NHibernateExtensionFacility(dataSourceConfiguration.Children["repositories"]));
        }

        public override void Register(Assembly assembly)
        {
            Container.Register(
                     AllTypes.FromAssembly(assembly)
                    .BasedOn(typeof(DataObject))
                    .WithService.Base()
                    .WithService.AllInterfaces()
                    .Configure(delegate(ComponentRegistration component)
                        {
                            component.LifeStyle.Transient.Named(component.Implementation.ToString());

                                Type dataObjectType = component.Implementation;
                                RepositoryConfigurationKeyDictionary repositoryConfigurationKeyDictionary = Container.Resolve<RepositoryConfigurationKeyDictionary>();
                                NHibernate.Cfg.Configuration configuration = Container.Resolve<NHibernate.Cfg.Configuration>(repositoryConfigurationKeyDictionary.GetDatabaseName(dataObjectType) + ".cfg");
                                Stream cfgStream = null;
                                if (assembly.GetManifestResourceInfo(dataObjectType.FullName + ".hbm.xml") == null)
                                {
                                    cfgStream = assembly.GetManifestResourceStream(dataObjectType.FullName);
                                }
                                else
                                {
                                    cfgStream=
                                    assembly.GetManifestResourceStream(dataObjectType.FullName + ".hbm.xml");
                                }
                                using (cfgStream)
                                {
                                    configuration.AddInputStream(cfgStream);
                                }
                                if (IsDebug)
                                {
                                    SchemaUpdate schemaUpdate = new SchemaUpdate(configuration);
                                    schemaUpdate.Execute(false, true);
                                }

                        }),
               AllTypes.FromAssembly(assembly)
                    .BasedOn(typeof(DataObjectRepository<>))
                    .WithService.AllInterfaces()
                    .Configure(delegate(ComponentRegistration component)
                        {
                            component.LifeStyle.Transient
                                .OnCreate(BuildRepository);
                        }),

                Component.For(typeof(IRepository<>))
                     .Unless((kernel, model) => kernel.HasComponent(model.Service))
                    .ImplementedBy(typeof(DataObjectRepository<>))
                    .LifeStyle.Transient
                    .OnCreate(BuildRepository)
                    );


        }

        private void BuildRepository(IKernel kernel, object instance)
        {
            BaseRepository repository = instance as BaseRepository;
            if (repository == null)
            {
                if (repository.logger != null)
                {
                    repository.logger = Logger.Create(repository.GetType());
                }
                if (repository.sessionManager == null)
                {
                    //   repository.sessionManager = kernel.Resolve<ISessionManager>(instance.GetType().Name);
                }
            }
        }
    }
}
